/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.layers;

import java.util.Observable;
import java.util.Observer;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

import id.duapuluhdua.dakidaki.MainState;
import id.duapuluhdua.dakidaki.activities.ActivityMain;
import id.duapuluhdua.dakidaki.common.CommonActivity;
import id.duapuluhdua.dakidaki.gps.GpsLocation;
import id.duapuluhdua.dakidaki.gps.GpsLocationStatus;
import id.duapuluhdua.dakidaki.map.GeoPoint;
import id.duapuluhdua.dakidaki.map.Mercator;
import id.duapuluhdua.dakidaki.map.Screen;
import id.duapuluhdua.dakidaki.map.ScreenPoint;

/**
 *
 */
public abstract class Layer
{
  /** Fields */
  protected CommonActivity mParent;
  protected Screen mScreen;
  protected MainState mState;
  protected Context mContext;

  protected Paint mDefaultText;

  protected GeoPoint mLocationGeoPoint;
  protected ScreenPoint mLocationScreenPoint;

  private GpsLocation mGpsLocation;

  protected static long testLastFrameTime = 0;

  /**
   * The default constructor.
   *
   * @param parent The application activity.
   * @param screen The screen object.
   */
  public Layer(CommonActivity parent, Screen screen)
  {
    mParent = parent;
    mScreen = screen;
    mState = parent.getMainState();
    mContext = parent.getApplicationContext();

    mDefaultText = new Paint();
    mDefaultText.setAntiAlias(true);
    mDefaultText.setARGB(255, 0, 0, 0);

    mLocationGeoPoint = new GeoPoint();
    mLocationScreenPoint = new ScreenPoint();
    mGpsLocation = new GpsLocation();
  }

  public Screen getScreen()
  {
    return mScreen;
  }

  public boolean isLocationEnabled()
  {
    return mGpsLocation.isEnabled();
  }

  /**
   * Retrieve the location geo-point from GPS reading.
   *
   * @param observable
   * @param data
   */
  public void updateLocation(Observable observable, Object data)
  {
    if (observable instanceof GpsLocationStatus) {
      if (data == GpsLocationStatus.STATE_NEW_GPS_LOCATION) {
        synchronized(mLocationGeoPoint)
        {
          ActivityMain.loader.getGpsLocationStatus().copyCurrent(mGpsLocation);

          if (mGpsLocation.isEnabled()) {
            mLocationGeoPoint.wgsLon = mGpsLocation.wgsLon;
            mLocationGeoPoint.wgsLat = mGpsLocation.wgsLat;
            mLocationGeoPoint.accuracy = mGpsLocation.accuracy;

            Mercator.convertToFlat(mLocationGeoPoint);

            updateLocation();
          }
        }
      }
    }
  }

  public void updateLocation()
  {
    // Do nothing.
  }

  /**
   * Observe location status.
   *
   * @param observer
   */
  public void startObserveLocation(Observer observer)
  {
    ActivityMain.loader.getGpsLocationStatus().addObserver(observer);
  }

  protected void updateLocationScreenPoint()
  {
    synchronized(mLocationGeoPoint)
    {
      mScreen.toScreenPoint(mLocationGeoPoint, mLocationScreenPoint);
    }
  }

  /**
   * Implement the actions when the surface size changes.
   *
   * @param width
   * @param height
   * @param screenOrientation
   */
  public abstract void surfaceSizeChanged(int width, int height, int screenOrientation);

  /**
   * Each type of layer has its own way to initialize the data.
   */
  public abstract void initData();

  /**
   *
   * @param cs
   * @param rtBounds
   */
  public abstract void doDraw(Canvas cs, Rect rtBounds);

  /**
   *
   */
  public abstract void updateObjectsState();

}
